/* 
 * File:   Anilla.cpp
 * 
 * Grenera una Anilla que comprueba colisiones con la nave y se reusa de manera
 * independiente una vez incializada solo se necesita llamar a idle() cada tick
 * y a dibujar() cuando corresponda dibujar. toda la logica asociada se maneja
 * en esa clase quitando trabajo a Nave.cpp y main.cpp.
 */

#include "Anilla.hpp"
#define RADIO 10.0   // radio de la anilla
#define ZSPAWN -900  // distancia a la que debe aparecer la anilla 
#define ZKILL 100    // distancia a la que debe eliminar la anilla (y reusarse)
#define GROSOR 0.9  // grosor del anillo.

/**
 * Constructor de la clase Anilla.
 * 
 * @param n : Apuntador a un objeto Nave con la que debe revisar colisiones.
 * @param p : Anilla Previa con la cual debe mantener apariencia de tunel.
 * @param w : Limite en el eje X.
 * @param h : Limite en el eje Y.
 */
Anilla::Anilla(Nave* n, Anilla* p, int w, int h) : ObjetoGrafico(0, 0, 100) {
    nave = n;
    prevAnilla = p;
    on = false;
    ancho_pantalla = abs(w - 1);
    alto_pantalla = abs(h - 1);

    // Se definen las propiedades visuales de la Anilla
    material_ambient[0] = 0.3;
    material_ambient[1] = 0.3;
    material_ambient[2] = 0.3;

    material_emision[0] = 0.0;
    material_emision[1] = 0.0;
    material_emision[2] = 0.0;

    material_especular[0] = 0.9;
    material_especular[1] = 0.9;
    material_especular[2] = 0.9;

    material_brillo[0] = 128.0;


    //cargar sonido para cuando se impacta el anillo
    cargarSonido("succes.wav", false);
}

/* Este metodo dibuja la Anilla en la escena.
 */
void Anilla::dibujar() {
    // se prepara para dibujar

    /*************DIBUJAR LA SOMBRA****************/

    glPushMatrix();
    //activamos la matriz de sombra
    activarModoSombra();
    
    glTranslatef(x, y, z);
    
    glutSolidTorus(GROSOR, RADIO, 20, 20);
    
    //desactivamos la configuracion de sombreado
    desactivarModoSombra();
    glPopMatrix();
    
    
    /*************DIBUJAR EL ANILLO****************/

    glPushMatrix();

    glTranslatef(x, y, z);


    //escoje el color de la anilla
    if (z < 0) { // si la anilla aun no ha pasado la nave
        // Amarillo
        material_difuso[0] = 1.0;
        material_difuso[1] = 1.0;
        material_difuso[2] = 0.0;
    } else if (on) { // si la anilla fue atravezada por la nave
        // Verde
        material_difuso[0] = 0.0;
        material_difuso[1] = 1.0;
        material_difuso[2] = 0.0;
    } else { // si la nave ha fallado en atravezar la anilla
        // Rojo
        material_difuso[0] = 1.0;
        material_difuso[1] = 0.0;
        material_difuso[2] = 0.0;
    }
    // se aplican las propiedades visuales del material
    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, material_ambient);
    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, material_difuso);
    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, material_especular);
    glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, material_emision);
    glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, material_brillo);

    // se dibuja la anilla
    glutSolidTorus(GROSOR, RADIO, 30, 30);

    // se termina de dibujar
    glPopMatrix();
}

/**
 * Este metodo idle permite a la Anilla moverse y realizar los
 * calculos de colision
 * @param s : El frameskip actual.
*/

void Anilla::idle(int s) {
    z += s; //la velocidad de una anilla es 1 unidad en z cada tick.

    if (z >= ZKILL) {
        newPos(); //Al llegar a ZKILL la anilla es reutilizada
    }

    if (0 <= z && z < s) { // se supone que la Nave se encuentra en Z=0
        // se calcula la distancia entre la anilla y la nave en XY
        float xd = abs(x - nave->getX());
        float yd = abs(y - nave->getY());
        float vl = Vlenght(xd, yd);

        // si se encuentra dentro del radio de colision
        if (vl < RADIO) {
            nave->addScore(1); // suma 1 al score
            on = true; // se activa el flag de que ha sido atravezada
            alSourcePlay(source[0]);
        }
    }
}

/**
 *  Le asigna una nueva posicion a la anilla de manera semi aleatoria
 * efectivamente reutilizandola.
 *  
 */
void Anilla::newPos() {

    int rx = rand() % 16 - 8; // -8<rx<8
    int ry = rand() % 12 - 6; // -8<ry<8


    if (prevAnilla == NULL) { // Es la primera anilla de un tunel.
        // se le asigna una posicion semi aleatoria a la anilla
        x += (abs(rx + ancho_pantalla) % (ancho_pantalla * 2)) - ancho_pantalla; // -ancho<x<ancho
        y += (abs(ry + alto_pantalla) % (alto_pantalla * 2)) - alto_pantalla; // -alto<y<alto

        z = ZSPAWN;
    } else { // Es parte de un tunel.
        // se calcula una posicion relativa a la anilla anterior
        x = prevAnilla->x + (abs(rx + ancho_pantalla) % (ancho_pantalla * 2)) - ancho_pantalla;
        y = prevAnilla->y + (abs(ry + alto_pantalla) % (alto_pantalla * 2)) - alto_pantalla;
        z = prevAnilla->z - 200;
    }
    //se reinician las variables pertinentes
    on = false;
}


/**
 * Esta funcion auxiliar calcula la magnitud de un vector con origen en (0,0).
 *  
 * @param x : La posicion del punto en el eje X.
 * @param y : La posicion del punto en el eje Y.
 * @return El modulo del vector.
 */
float Anilla::Vlenght(float x, float y) {
    return sqrt(x * x + y * y);
}

/**
 * Funcion Debug
 * imprime por consola informacion de la anilla 
 */
void Anilla::print() {
    std::cout << "Anilla(" << this << "," << x << "," << y << "," << z << "," << prevAnilla << ")" << std::endl;
}
